package dmxGroupControl;

import java.util.TreeMap;
import java.util.Map.Entry;

import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;

import org.jdom2.Element;

public class DMXFixture extends Fixture
{
	protected Label debugText;

	private Rectangle rect;
	private Line panLine, tiltLine;
	private int channelStart;
    Color displayColor;
    boolean externallyControlledColor = false;

	public DMXFixture(String name, Element groupEntry, int startChannel)
	{
		super(name, groupEntry);
		channelStart = startChannel;
		
		Element definitionElement = LightController.GetFixtureDefinition(name); 
		if(definitionElement != null)
		{
		    channels = new ChannelCollection(startChannel, definitionElement);
		}
        else
        {
            System.err.println("Fixture [" + name + "] not found in fixture definition file");
        }
        displayColor = Color.BLACK;
	}

	public DMXFixture(String name, int startChannel)
	{
		super(name);
		channelStart = startChannel;
        displayColor = Color.BLACK;
	}

    public void SetDisplayColor(Color color)
    {
        this.displayColor = color;
        externallyControlledColor = true;
    }
	
	public TreeMap<Integer, Integer> GetDMXChannels()
	{
		TreeMap<Integer, Integer> output = new TreeMap<>();

		for (Channel channel : channels)
		{
		    if (channel.GetName().equalsIgnoreCase("Master") && GetIsSharedStrobe()
					&& GetIsStrobing())
			{
				// we'll get to this channel in a moment
			}
		    else if(channel.GetName().equalsIgnoreCase("Strobe") && GetIsSharedStrobe()
                    && !GetIsStrobing())
		    {
		        // we've already dealt with this channel
		    }
			else
			{
				output.put(channel.GetDMXChannel(), channel.GetDMXValue());
			}
		}

		if (debugTextOption != DebugTextOptions.NONE)
		{
			UpdateLabel(debugText, output, debugTextOption);
		}
		
		return output;
	}

	public void SetRect(Rectangle rect)
	{
		this.rect = rect;
		rect.setOnMouseClicked((event) -> {
			debugTextOption = debugTextOption.Next();
			if (debugText != null)
			{
				debugText.setText("");
			}
		});
	}

	public void SetDebugLabel(Label label)
	{
		debugText = label;
	}
	
	public void SetPanLine(Line panLine)
	{
	    this.panLine = panLine;
	}
	
	public void SetTiltLine(Line tiltLine)
    {
	    this.tiltLine = tiltLine;
    }
	
	protected void UpdateLabel(Label label, TreeMap<Integer, Integer> values,
			DebugTextOptions nameOption)
	{
		String debugString = "";
		for (Entry<Integer, Integer> entry : values.entrySet())
		{
			String name = "";
			switch (nameOption)
			{
			case NAMES:
				name = GetNameForDMX(entry.getKey());
				break;
			case CHANNELS:
				name = entry.getKey().toString();
				break;
			case NONE:
				return;
			}

			debugString += name + " = " + entry.getValue() + "\r\n";
		}

		final String debugStringToPass = debugString;
		final Label debugLabel = label;

		if (debugText != null)
		{
			Platform.runLater(() -> debugLabel.setText(debugStringToPass));
		}
	}

	@Override
	public void UpdateDisplay()
	{
		javafx.scene.paint.Color colorToPaint;

		if (GetIsStrobing() && LightController.strobeOn)
		{
			colorToPaint = javafx.scene.paint.Color.BLACK;
		}
        else if(externallyControlledColor)
        {
            colorToPaint = displayColor;
        }
		else
		{
			if (IsColor())
			{
				float red = channels.OptionalGetChannel("Red");
				float green = channels.OptionalGetChannel("Green");
				float blue = channels.OptionalGetChannel("Blue");

				colorToPaint = Color.color(red, green, blue);
			}
			else if (channels.Contains("White"))
			{
				colorToPaint = Color.gray(channels.GetChannel("White")
						.GetValue());
			}
			else
			{
				colorToPaint = Color.gray(channels.OptionalGetChannel("Master"));
			}

		}

		final javafx.scene.paint.Color colorToPass = colorToPaint;

		if (rect != null)
		{
			Platform.runLater(() -> rect.setFill(colorToPass));
		}
		
		if(panLine != null && !Float.isNaN(channels.OptionalGetChannel("Pan")))
		{
		    double left = rect.getX();
            double width = rect.getWidth();
            double xOffset = channels.OptionalGetChannel("Pan") * width;
            final double x = left + xOffset;
            Platform.runLater(() -> StackPane.setMargin(panLine, new Insets(0, width - x, 0, x)));
            
		}
		
		if(tiltLine != null && !Float.isNaN(channels.OptionalGetChannel("Tilt")))
		{
		    double top = rect.getY();
            double height = rect.getHeight();
            double yOffset = channels.OptionalGetChannel("Tilt") * height;
            final double y = top + yOffset;
            Platform.runLater(() -> StackPane.setMargin(tiltLine, new Insets(y, 0, height - y, 0)));
		}
	}
	
	public int GetChannelStart()
	{
		return channelStart;
	}
	
	public int GetChannelEnd()
    {
        if(channels.isEmpty())
            return GetChannelStart();
        return channels.GetLast().GetDMXChannel();
    }
	
	public void SetStartChannel(int value)
    {
        int oldChannelStart = channelStart;
        channelStart = value;
        int difference = value - oldChannelStart;
        channels.Reposition(difference);
    }
	
	@Override public String toString() 
	{
		return "[" + channelStart + " - " + (channelStart + GetChannelCount() - 1) + "] " + GetName();
	}
}
